/**
 * 
 */
package galacticthrone.screen.map;

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;

import galacticthrone.empire.Empire;
import galacticthrone.main.GTGame;
import galacticthrone.map.GalacticMap;
import galacticthrone.map.data.obs.Fleet;
import galacticthrone.map.data.obs.Ob;
import galacticthrone.map.data.obs.SolarSystem;
import galacticthrone.map.render.MapIcon;
import galacticthrone.properties.Paths;
import galacticthrone.screen.MouseCursor;
import javagame.core.io.Screen;
import javagame.core.io.keyboard.KeyActionMap;
import javagame.core.main.Time;
import javagame.impl.io.keyboard.ActionMapping;
import javagame.impl.io.keyboard.KeyBinding;
import javagame.impl.io.video.screen.ClearScreen;

// TODO Javadoc
/**
 * <br>
 *
 * @author Jaco van der Westhuizen
 */
public class MapScreen extends Screen
{
	private static enum State
	{
		DEFAULT,
		SYSTEM_SELECTED,
		FLEET_SELECTED,
		INFO_SHOW,
		SYSTEM_MENU;
	}
	
	private static enum KeyAction implements ActionMapping
	{
		SCROLL_WEST (KeyEvent.VK_LEFT,  "SCROLL_WEST"),
		SCROLL_EAST (KeyEvent.VK_RIGHT, "SCROLL_EAST"),
		SCROLL_NORTH(KeyEvent.VK_UP,    "SCROLL_NORTH"),
		SCROLL_SOUTH(KeyEvent.VK_DOWN,  "SCROLL_SOUTH");

		private final int key;
		private final String name;

		private KeyAction(int key, String name)
		{
		    this.key = key;
		    this.name = name;
		}

        /* (non-Javadoc)
         * @see javagame.impl.io.keyboard.ActionMapping#getDefaultKey()
         */
        @Override
        public int getDefaultKey()
        {
            return key;
        }

        /* (non-Javadoc)
         * @see javagame.impl.io.keyboard.ActionMapping#getText()
         */
        @Override
        public String getText()
        {
            return name;
        }
	}

	private static final KeyActionMap<ActionMapping> KEYS = new KeyBinding("mapscreen.keys", KeyAction.values());
    private static final int INDEX_MAP = 2; // See the constructor

    static final int INDEX_MAP_GRID = 0;
    static final int INDEX_MAP_OBS  = 1;

	private final MapRenderer map = new MapRenderer(0, 0, 1);
    private final MouseCursor cursor = new MouseCursor(Paths.TEXTURES + "Mouse.png", 32, 4, 28); 

    private State state = State.DEFAULT;
    Ob selection = null;
    
    byte scrollX = 0;
    byte scrollY = 0;
    byte scrollZ = 0;

    public MapScreen()
    {
        super(true);

        this.addScreenRenderer(new ClearScreen());   // 0
        this.addScreenRenderer(new StarField(map));  // 1
        this.addScreenRenderer(map);                 // 2
        this.addScreenRenderer(cursor);              // 3
    }

    /* (non-Javadoc)
     * @see javagame.core.io.Screen#getKeyActionMap()
     */
    @Override
    public KeyActionMap<ActionMapping> getKeyActionMap()
    {
        return KEYS;
    }

    /* (non-Javadoc)
     * @see javagame.core.io.Screen#onKeyActionOn(java.lang.Object)
     */
    @Override
    public void onKeyActionOn(Object action)
    {
    	if (!(action instanceof KeyAction))
    		throw new IllegalArgumentException("MapScreen.onKeyActionOff only accepts MapScreen.KeyAction objects.");

    	switch ((KeyAction)action)
    	{
    		case SCROLL_NORTH:
    		{
    			scrollY = +1;
    			break;
    		}
    		case SCROLL_SOUTH:
    		{
    			scrollY = -1;
    			break;
    		}
    		case SCROLL_EAST:
    		{
    			scrollX = +1;
    			break;
    		}
    		case SCROLL_WEST:
    		{
    			scrollX = -1;
    			break;
    		}
    	}
    }

    /* (non-Javadoc)
     * @see javagame.core.io.Screen#onKeyActionOff(java.lang.Object)
     */
    @Override
    public void onKeyActionOff(Object action)
    {
    	if (!(action instanceof KeyAction))
    		throw new IllegalArgumentException("MapScreen.onKeyActionOff only accepts MapScreen.KeyAction objects.");

    	switch ((KeyAction)action)
    	{
    		case SCROLL_NORTH:
    		{
    			scrollY = 0;
    			break;
    		}
    		case SCROLL_SOUTH:
    		{
    			scrollY = 0;
    			break;
    		}
    		case SCROLL_EAST:
    		{
    			scrollX = 0;
    			break;
    		}
    		case SCROLL_WEST:
    		{
    			scrollX = 0;
    			break;
    		}
    	}
    }

    /* (non-Javadoc)
     * @see javagame.core.io.Screen#onCharTyped(char)
     */
    @Override
    public void onCharTyped(char character)
    {
        switch (character)
        {
            // TODO Other keys
            case 'x':
            case 'X':
            {
                // TODO Remove this and make menu
                GTGame.get().exit();
            }
        }
    }

    /* (non-Javadoc)
     * @see javagame.core.io.Screen#onMouseDown(int)
     */
    @Override
    public void onMouseDown(int button)
    {
        if ((mouseCache == null) || (mouseCache.length < 2))
        	return;

        switch (mouseCache[0])
        {
        	case INDEX_MAP:
        	{
                switch (mouseCache[1])
                {
                	case INDEX_MAP_GRID:
                	{
                		switch (button)
                		{
                			case MouseEvent.BUTTON3:
                			{
                				// Scroll view
                				if (mouseCache.length >= 4)
                				{
                					map.centerOn(mouseCache[2], mouseCache[3]);
                				}
                				break;
                			}
                		}
                		break;
                	}
                	case INDEX_MAP_OBS:
                	{
                		Ob newSel = null;
                		switch (button)
                		{
                			case MouseEvent.BUTTON1:
                			{
                				// Select the Ob
                				if (mouseCache.length >= 3)
                					newSel = MapIcon.lookup(mouseCache[2]).getOb();
                				else
                				{
                					setState(State.DEFAULT);
                					break;
                				}

                				if (newSel instanceof SolarSystem)
                					setState(State.SYSTEM_SELECTED);
                				
                				if (newSel instanceof Fleet)
                					setState(State.FLEET_SELECTED);

                				break;
                			}
                			case MouseEvent.BUTTON3:
                			{
                				// Show Ob info
                				if (mouseCache.length >= 3)
                				{
                					newSel = MapIcon.lookup(mouseCache[2]).getOb();
                					setState(State.INFO_SHOW);
                    			}
                				else
                				{
                					setState(State.DEFAULT);
                				}

                				break;
                			}
                		}
                		
                		if (newSel != null)
                		{
                			map.centerOn(newSel);
                		}
            			selection = newSel;

            			break;
                	}
                }
                break;
			}
        	// TODO UI Clicks
		}
	}

	/* (non-Javadoc)
     * @see javagame.core.io.Screen#onMouseUp(int)
     */
    @Override
    public void onMouseUp(int button)
    {
    }

    /* (non-Javadoc)
     * @see javagame.core.io.Screen#onMouseWheel(int)
     */
    @Override
    public void onMouseWheel(int diff)
    {
		map.zoomStep(diff);
    }

    /* (non-Javadoc)
     * @see javagame.core.io.Screen#onMousePick()
     */
    @Override
    public void onMousePick()
    {
    }

    /* (non-Javadoc)
     * @see javagame.core.io.Screen#onMouseMove()
     */
    @Override
    public void onMouseMove()
    {
        cursor.setVisible(isMouseOver);
        cursor.moveTo(this.mouseX, this.mouseY);
    }

    /* (non-Javadoc)
     * @see javagame.core.main.time.Temporal#update(javagame.core.main.time.Time)
     */
    @Override
    public void update(Time time)
    {
    	if ((scrollX != 0)
    	 || (scrollY != 0)
    	 || (scrollZ != 0))
    	{
    		float delta = time.getElapsed().getSeconds();
    		map.scroll(scrollX * delta, scrollY * delta, scrollZ * delta);
    	}

        super.update(time);
    }

    /**
     * @param gameMap
     */
    void setMap(GalacticMap gmap)
    {
    	Empire player = gmap.getPlayerEmpire();
        map.setMap(player.getMap());

        map.setParams(player.getHomeWorld().getPosX(),
        		      player.getHomeWorld().getPosY(), 20);
    }

    /**
     * @param newState The new state.
     */
    private void setState(State newState)
    {
	    this.state = newState;
	    
	    // TODO Switch on/off GUIs
	    switch (state)
	    {
	    	case DEFAULT:
	    	{
	    		break;
	    	}
	    	case SYSTEM_SELECTED:
	    	{
	    		break;
	    	}
	    	case FLEET_SELECTED:
	    	{
	    		break;
	    	}
	    	case INFO_SHOW:
	    	{
	    		break;
	    	}
	    }
    }
}
